package com.rustic.server.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.xy.commons.enums.DisableStatus;
import cn.xy.commons.exception.JzRuntimeException;
import cn.xy.commons.util.StringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rustic.server.dao.TravelPlanDao;
import com.rustic.server.dto.TravelPlanAddDTO;
import com.rustic.server.dto.TravelPlanAuditDTO;
import com.rustic.server.dto.TravelPlanUpdateDTO;
import com.rustic.server.enums.AuditStatus;
import com.rustic.server.enums.LinkType;
import com.rustic.server.po.Rustic;
import com.rustic.server.po.TravelPlan;
import com.rustic.server.po.User;
import com.rustic.server.po.UserCollectionLink;
import com.rustic.server.po.UserLikeLink;
import com.rustic.server.query.TravelPlanAdminListQuery;
import com.rustic.server.query.TravelPlanUserListQuery;
import com.rustic.server.service.RusticService;
import com.rustic.server.service.TravelPlanService;
import com.rustic.server.service.UserBrowseLinkService;
import com.rustic.server.service.UserCollectionLinkService;
import com.rustic.server.service.UserLikeLinkService;
import com.rustic.server.service.UserService;
import com.rustic.server.vo.TravelPlanWebVO;
import com.rustic.server.vo.list.TravelPlanAdminListVO;
import com.rustic.server.vo.list.TravelPlanWebListVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * TravelPlan对应的服务类实现
 *
 * @author auto
 */

@Slf4j
@Service
public class TravelPlanServiceImpl extends ServiceImpl<TravelPlanDao, TravelPlan> implements TravelPlanService {

    @Autowired
    private RusticService rusticService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserLikeLinkService userLikeLinkService;

    @Autowired
    private UserCollectionLinkService userCollectionLinkService;

    @Autowired
    private UserBrowseLinkService userBrowseLinkService;

    @Override
    public List<TravelPlan> listByIdIn(List<Integer> idList) {
        if (CollUtil.isEmpty(idList)) {
            return new ArrayList<>();
        }
        return this.listByIds(idList);
    }

    @Override
    public Map<Integer, TravelPlan> mapByIdIn(List<Integer> idList) {
        List<TravelPlan> travelPlanList = this.listByIdIn(idList);
        return travelPlanList.stream().collect(Collectors.toMap(TravelPlan::getId, b -> b));
    }

    @Override
    public LambdaQueryWrapper<TravelPlan> toAdminListWrapper(TravelPlanAdminListQuery query) {
        LambdaQueryWrapper<TravelPlan> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(TravelPlan::getRusticId, query.getRusticId());
        queryWrapper.like(CharSequenceUtil.isNotEmpty(query.getName()), TravelPlan::getName, query.getName());
        queryWrapper.like(CharSequenceUtil.isNotEmpty(query.getCreator()), TravelPlan::getCreator, query.getCreator());
        queryWrapper.eq(query.getStatus() > 0, TravelPlan::getStatus, query.getStatus());
        if (CharSequenceUtil.isNotEmpty(query.getAuditStatus())) {
            List<String> auditStatusList = StringUtil.splitToList(query.getAuditStatus());
            queryWrapper.in(CollUtil.isNotEmpty(auditStatusList), TravelPlan::getAuditStatus, auditStatusList);
        }
        queryWrapper.gt(query.getStartAuditTime() != null, TravelPlan::getAuditTime, query.getStartAuditTime());
        queryWrapper.lt(query.getEndAuditTime() != null, TravelPlan::getAuditTime, query.getEndAuditTime());
        queryWrapper.gt(query.getStartPublishTime() != null, TravelPlan::getPublishTime, query.getStartPublishTime());
        queryWrapper.lt(query.getEndPublishTime() != null, TravelPlan::getPublishTime, query.getEndPublishTime());
        queryWrapper.gt(query.getStartUpdateTime() != null, TravelPlan::getUpdateTime, query.getStartUpdateTime());
        queryWrapper.lt(query.getEndUpdateTime() != null, TravelPlan::getUpdateTime, query.getEndUpdateTime());
        // 添加排除状态为4的条件
        queryWrapper.ne(TravelPlan::getAuditStatus, AuditStatus.WITHHOLD.getValue());
        //FIXME 时间的排顺序，是更新时间还是发布时间
        queryWrapper.orderByAsc(TravelPlan::getUpdateTime);
        return queryWrapper;
    }

    @Override
    public List<TravelPlanAdminListVO> toAdminListVo(List<TravelPlan> travelPlanList) {
        List<TravelPlanAdminListVO> results = new ArrayList<>();
        for (TravelPlan travelPlan : travelPlanList) {
            TravelPlanAdminListVO travelPlanAdminListVO = new TravelPlanAdminListVO(travelPlan);
            results.add(travelPlanAdminListVO);
        }
        return results;
    }

    @Override
    public List<TravelPlanWebListVO> toWebListVo(List<TravelPlan> travelPlanList, int userId) {
        List<Integer> travelPlanIdList = travelPlanList.stream().map(TravelPlan::getId).collect(Collectors.toList());
        Map<Integer, Long> likeCountMap = userLikeLinkService.mapByTargetIdAndType(travelPlanIdList, LinkType.TRAVEL_PLAN);
        Map<Integer, Long> collectionCountMap = userCollectionLinkService.mapByTargetIdAndType(travelPlanIdList, LinkType.TRAVEL_PLAN);
        Map<Integer, Long> browseCountMap = userBrowseLinkService.mapByTargetIdAndType(travelPlanIdList, LinkType.TRAVEL_PLAN);
        // 用户是否有点赞收藏
        Map<Integer, UserLikeLink> userLikeMap = userLikeLinkService.mapByUserTargetAndType(travelPlanIdList, LinkType.TRAVEL_PLAN, userId);
        Map<Integer, UserCollectionLink> userCollectionMap = userCollectionLinkService.mapByUserTargetAndType
                (travelPlanIdList, LinkType.TRAVEL_PLAN, userId);
        // 查询景点对应的乡村
        List<Integer> rusticIdList = travelPlanList.stream().map(TravelPlan::getRusticId).collect(Collectors.toList());
        Map<Integer, Rustic> rusticMap = rusticService.mapByIdIn(rusticIdList);
        return travelPlanList.stream().map(item -> {
            TravelPlanWebListVO travelPlanWebVO = new TravelPlanWebListVO(item);
            // 得到点赞的数量
            if (likeCountMap.get(item.getId()) != null) {
                travelPlanWebVO.setLikeCount(likeCountMap.get(item.getId()));
            }
            // 收藏的数量
            if (collectionCountMap.get(item.getId()) != null) {
                travelPlanWebVO.setCollectionCount(collectionCountMap.get(item.getId()));
            }
            // 浏览数量
            if (browseCountMap.get(item.getId()) != null) {
                travelPlanWebVO.setBrowseCount(browseCountMap.get(item.getId()));
            }
            // 用户是否点赞
            if (userLikeMap.get(item.getId()) != null) {
                travelPlanWebVO.setLike(true);
            }
            // 用户是否收藏
            if (userCollectionMap.get(item.getId()) != null) {
                travelPlanWebVO.setCollection(true);
            }
            // 填充对应的乡村名称
            Rustic rustic = rusticMap.get(item.getRusticId());
            if (rustic != null) {
                travelPlanWebVO.setRusticName(rustic.getName());
            }
            return travelPlanWebVO;
        }).collect(Collectors.toList());
    }

    @Override
    public LambdaQueryWrapper<TravelPlan> toUserListWrapper(TravelPlanUserListQuery query) {
        LambdaQueryWrapper<TravelPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(TravelPlan::getId, TravelPlan::getRusticId, TravelPlan::getName, TravelPlan::getCreator,
                TravelPlan::getCreatorId, TravelPlan::getCover, TravelPlan::getPublishTime, TravelPlan::getUpdateTime, TravelPlan::getCreateTime);
        queryWrapper.eq(query.getRusticId() > 0, TravelPlan::getRusticId, query.getRusticId());
        queryWrapper.like(CharSequenceUtil.isNotEmpty(query.getName()), TravelPlan::getName, query.getName());
        queryWrapper.like(CharSequenceUtil.isNotEmpty(query.getCreator()), TravelPlan::getCreator, query.getCreator());
        queryWrapper.eq(TravelPlan::getStatus, DisableStatus.NORMAL.getValue());
        queryWrapper.eq(TravelPlan::getAuditStatus, AuditStatus.PASS.getValue());
        queryWrapper.orderByDesc(TravelPlan::getPublishTime);
        return queryWrapper;
    }

    @Override
    public LambdaQueryWrapper<TravelPlan> toUserWorksListWrapper(TravelPlanUserListQuery query, int userId) {
        LambdaQueryWrapper<TravelPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(TravelPlan::getId, TravelPlan::getRusticId, TravelPlan::getName, TravelPlan::getCreator, TravelPlan::getAuditStatus,
                TravelPlan::getCreatorId, TravelPlan::getCover, TravelPlan::getPublishTime, TravelPlan::getUpdateTime, TravelPlan::getCreateTime);
        queryWrapper.like(CharSequenceUtil.isNotEmpty(query.getName()), TravelPlan::getName, query.getName());
        queryWrapper.eq(TravelPlan::getCreatorId, userId);
        queryWrapper.orderByDesc(TravelPlan::getPublishTime);
        return queryWrapper;
    }

    @Override
    public void add(TravelPlanAddDTO travelPlanAddDTO, int userId) {
        Rustic rustic = rusticService.getById(travelPlanAddDTO.getRusticId());
        if (rustic == null) {
            throw new JzRuntimeException(RusticService.RUSTIC_NOT_EXIST);
        }
        User user = userService.getById(userId);
        if (user == null) {
            throw new JzRuntimeException(UserService.USER_NOT_EXIST);
        }
        TravelPlan travelPlan = travelPlanAddDTO.toTravelPlan();
        travelPlan.setCreator(user.getNickname());
        travelPlan.setCreatorId(userId);
        travelPlan.setStatus(DisableStatus.NORMAL.getValue());
        travelPlan.setAuditStatus(AuditStatus.WAIT.getValue());
        travelPlan.setPublishTime(new Date());
        this.save(travelPlan);
    }

    @Override
    public void update(TravelPlanUpdateDTO travelPlanUpdateDTO, int userId) {
        TravelPlan travelPlan = this.getById(travelPlanUpdateDTO.getId());
        if (travelPlan == null) {
            throw new JzRuntimeException(TravelPlanService.TRAVEL_PLAN_NOT_EXIST);
        }
        if (travelPlan.getCreatorId() != userId) {
            throw new JzRuntimeException("非本人作品，不能修改!");
        }
        Rustic rustic = rusticService.getById(travelPlanUpdateDTO.getRusticId());
        if (rustic == null) {
            throw new JzRuntimeException(RusticService.RUSTIC_NOT_EXIST);
        }
        User user = userService.getById(userId);
        if (user == null) {
            throw new JzRuntimeException(UserService.USER_NOT_EXIST);
        }
        this.update(new LambdaUpdateWrapper<TravelPlan>()
                .eq(TravelPlan::getCreatorId, userId)
                .eq(TravelPlan::getId, travelPlanUpdateDTO.getId())
                .set(TravelPlan::getName, travelPlanUpdateDTO.getName())
                .set(TravelPlan::getRusticId, travelPlanUpdateDTO.getRusticId())
                .set(TravelPlan::getCover, travelPlanUpdateDTO.getCover())
                .set(TravelPlan::getImages, travelPlanUpdateDTO.getImages())
                .set(TravelPlan::getIntroduce, travelPlanUpdateDTO.getIntroduce())
                .set(TravelPlan::getStatus, DisableStatus.NORMAL.getValue())
                .set(TravelPlan::getAuditStatus, AuditStatus.WAIT.getValue())
                .set(TravelPlan::getUpdateTime, new Date())
                .set(TravelPlan::getPublishTime, travelPlan.getAuditStatus() == AuditStatus.PASS.getValue() ? travelPlan.getPublishTime() : new Date())
                .set(TravelPlan::getAuditor, "")
                .set(TravelPlan::getAuditId, 0)
                .set(TravelPlan::getAuditRemark, "")
                .set(TravelPlan::getAuditTime, null));
    }

    @Override
    public void audit(TravelPlanAuditDTO travelPlanAuditDTO, int adminId, String username) {
        TravelPlan travelPlan = this.getById(travelPlanAuditDTO.getId());
        if (travelPlan == null) {
            throw new JzRuntimeException(TravelPlanService.TRAVEL_PLAN_NOT_EXIST);
        }
        // 填写统一的信息
        travelPlan.setAuditId(adminId);
        travelPlan.setAuditor(username);
        travelPlan.setAuditTime(new Date());
        // 审核不通过
        if (travelPlanAuditDTO.getAuditStatus() == AuditStatus.FAIL.getValue()) {
            // 判断是否有填写备注
            if (CharSequenceUtil.isEmpty(travelPlanAuditDTO.getAuditRemark())) {
                throw new JzRuntimeException("审核不通过，请填写备注!");
            }
            travelPlan.setAuditStatus(AuditStatus.FAIL.getValue());
            travelPlan.setStatus(DisableStatus.DISABLE.getValue());
        } else {
            // 审核通过
            travelPlan.setAuditStatus(AuditStatus.PASS.getValue());
            travelPlan.setStatus(DisableStatus.NORMAL.getValue());
        }
        travelPlan.setAuditRemark(travelPlanAuditDTO.getAuditRemark());
        this.updateById(travelPlan);
    }

    @Override
    public TravelPlanWebVO getByIdToWeb(int id) {
        TravelPlan travelPlan = this.getOne(new LambdaQueryWrapper<TravelPlan>()
                .eq(TravelPlan::getId, id)
                .eq(TravelPlan::getStatus, DisableStatus.NORMAL.getValue()));
        if (travelPlan == null) {
            throw new JzRuntimeException(TravelPlanService.TRAVEL_PLAN_NOT_EXIST);
        }
        TravelPlanWebVO travelPlanWebVO = new TravelPlanWebVO(travelPlan);
        // 填写乡村名称
        Rustic rustic = rusticService.getById(travelPlan.getRusticId());
        travelPlanWebVO.setRusticName(rustic != null ? rustic.getName() : "");
        return travelPlanWebVO;
    }

    @Override
    public TravelPlanWebVO getByIdToCreator(int id, int userId) {
        TravelPlan travelPlan = this.getOne(new LambdaQueryWrapper<TravelPlan>()
                .eq(TravelPlan::getId, id)
                .eq(TravelPlan::getCreatorId, userId));
        if (travelPlan == null) {
            throw new JzRuntimeException(TravelPlanService.TRAVEL_PLAN_NOT_EXIST);
        }
        TravelPlanWebVO travelPlanWebVO = new TravelPlanWebVO(travelPlan);
        // 填写乡村名称
        Rustic rustic = rusticService.getById(travelPlan.getRusticId());
        travelPlanWebVO.setRusticName(rustic != null ? rustic.getName() : "");
        return travelPlanWebVO;
    }
}
